

class TelnetCommand(object):
    __slots__ = ('val', 'opt', 'arg')

class TelnetConnection(object):
    
    def __init__(self):
        self.poller = AsyncIOPoller(self)
        self.ios = None
##    def connect(self):
##        pass
##    def close(self):
##        pass
    def open(self, addr):
        self.ios = socketio.open(addr, 'rwbs', 0, timeout=0)
        self.poller.register(self.ios)
    
    def set_handler(self, opt, hand):
        pass
    
    def send(self, data):
        IAC = TelCmd.IAC
        if type(data) is bytes:
            data = data.replace(IAC, IAC+IAC)
        else:
            data = str(data)
        with self.asyncmgr.lock:
            self.sendqueue.push(data)
            self.asyncmgr.set_writable(self.sock, True)
        
    def recv(self, data):
        pass

    # methods called by AsyncManager from async thread
    def do_connect(self, ios):
        pass
    
    def do_write(self, ios):
        data = bytes.join(b'', self.sendqueue)
        for xform in self.wxforms:
            data = xform(data)
        data = self.sendleft + data
        count = ios.write(data) or 0
        self.sendleft = data[count:]
        with self.asyncmgr.lock:
            flag = bool(self.sendleft) or bool(self.sendqueue)
            self.asyncmgr.set_writable(sock, flag)
    
    def do_read(self, ios):
        data = ios.read(BUFFER_SIZE)
        urgmod = not ios.atmark()
        for xform in self.rxforms:
            data = xform(data)
        res = self.parse_telcmd(data, urgmod)
        self.recv(res)
        
    def parse_telcmd(self, data, urgmod):
        IAC = TelCmd.IAC
        SB = TelCmd.SB
        SE = TelCmd.SE
        state = self.state
        telcmd = self.telcmd
        
        idx = 0
        end = len(data)
        while idx < end:
            if state == 0:
                jdx = data.find(IAC, idx)
                if jdx == -1:
                    if not urgmod:
                        self.on_recv_data(data[idx:])
                    break
                if not urgmod:
                    self.on_recv_data(data[idx:jdx])
                state = 1
                idx = jdx
            elif state == 1:
                val = data[idx]
                if val == IAC:
                    if not urgmod:
                        self.on_recv_data(val)
                    state = 0
                elif val >= SB:
                    telcmd = TelnetCommand(val)
                    #cmds.append(telcmd)
                    state = 2
                else:
                    if val in self.cmd_map:
                        if self.cmd_map[val]():
                            cmds.append(TelnetCommand(val))
                    else:
                        cmds.append(TelnetError())
                    state = 0
            elif state == 2:
                telcmd.opt = data[idx]
                if telcmd.val == SB:
                    state = 3
                else:
                    state = 0
                    handle_cmd
            elif state == 3:
                jdx = data.find(IAC, idx)
                if jdx == -1:
                    telcmd.arg += data[idx:]
                    pass
                    break
                telcmd.arg += data[idx:jdx]
                state = 4
            elif state == 4:
                val = data[idx]
                if val == IAC:
                    telcmd.arg += val
                    state = 3
                elif val == SE:
                    state = 0
                    handle_cmd
                else:
                    # what to do with invalid IAC command inside
                    # of an IAC SB sequence?
                    pass
            idx += 1
            chunk = data[idx : jdx]
            chunks.append(chunk)
            self.telcmd = TelnetCommand()
            if jdx
            if data.find(
        